package com.bestcem.xm.ticket.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.ticket.dao.TemplateDao;
import com.bestcem.xm.ticket.dao.TicketConfigDao;
import com.bestcem.xm.ticket.dao.TicketDao;
import com.bestcem.xm.ticket.dao.TicketFlowDao;
import com.bestcem.xm.ticket.entity.mongo.Ticket;
import com.bestcem.xm.ticket.entity.mongo.TicketConfig;
import com.bestcem.xm.ticket.entity.mongo.TicketFlow;
import com.bestcem.xm.ticket.entity.mongo.TicketTemplateV2;
import com.bestcem.xm.ticket.enums.TicketFlowMatchConditionEnum;
import com.bestcem.xm.ticket.enums.TicketFlowStatusEnum;
import com.bestcem.xm.ticket.enums.TicketStatusEnum;
import com.bestcem.xm.ticket.enums.TicketTypeEnum;
import com.bestcem.xm.ticket.service.dto.ticket.CreateTicketDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;

import static com.bestcem.xm.common.core.uitls.DateUtil.DATETIME_PATTERN_FORTICKETNO;

/**
 * 工单util
 *
 * @author jy.zhao
 * @version 1.0
 * @date 2021/8/17 21:11
 **/
@Slf4j
@Service
public class TicketUtil {

    @Resource
    private TicketConfigDao ticketConfigDao;
    @Resource
    private TicketFlowDao ticketFlowDao;
    @Resource
    private TemplateDao templateDao;
    @Resource
    private TicketDao ticketDao;
    @Autowired
    private RedisService redisService;

    /**
     * 创建工单
     *
     * @param ticketDTO 创建工单dto
     * @return String
     * @author jy.zhao
     * @date 2021/8/17 18:08
     **/
    public Ticket createTicket(CreateTicketDTO ticketDTO) {
        if (log.isInfoEnabled()) {
            log.info("[ticket] 创建工单请求：param={}", ticketDTO);
        }
        // 1 获取问卷的工单配置
        TicketConfig ticketConfig = ticketDTO.getTicketConfig();
        if (Validator.isNull(ticketConfig)) {
            log.error("[ticket] 没有找到id={}对应的工单配置", ticketDTO.getTicketConfigId());
            return null;
        }
        if (log.isInfoEnabled()) {
            log.info("[ticket] 工单配置：{}， 所属问卷：{}", ticketConfig.getId(), ticketDTO.getSurveyId());
        }
        // 兼容之前的预警规则商城工单。 调研是否仍然使用
        if (StringUtils.isNotEmpty(ticketDTO.getAlertId()) && !Objects.equals(ticketConfig.getAlertId(), ticketDTO.getAlertId())) {
            if (log.isInfoEnabled()) {
                log.info("当前的预警规则没有被工单配置所使用，不需要生成工单");
            }
            return null;
        }
        if (log.isInfoEnabled()) {
            log.info("[ticket] 获取工单跟进人信息：ticket_flow_id={}", ticketConfig.getTicketFlowIds());
        }
        // 2 获取配置中的工单流程
        TicketFlow ticketFlow = chooseTicketFlow(ticketConfig.getId(), ticketConfig.getTicketFlowIds());
        if (Objects.isNull(ticketFlow)) {
            log.error("[ticket] TicketConfig:{} no TicketFlow", ticketConfig.getId());
            return null;
        }
        if (log.isInfoEnabled()) {
            log.info("[ticket] 工单配置:{} 选择工单跟进人信息成功:{}", ticketConfig.getId(), ticketFlow.getId());
        }
        // 设置是否跟进处理。 不需要跟进处理的话就没有模板
        ticketDTO.setNeedDeal(ticketConfig.getNeedDeal());
        // 3 获取工单模板 工单模板一定会有模板
        TicketTemplateV2 ticketTemplate = null;
        if (Boolean.TRUE.equals(ticketDTO.getNeedDeal())) {
            ticketTemplate = templateDao.getTemplateById(ticketConfig.getTicketTemplateId());
            if (Objects.isNull(ticketTemplate)) {
                log.error("[ticket] TicketConfig:{} no ticketTemplate", ticketConfig.getId());
                return null;
            }
        }
        if (log.isInfoEnabled()) {
            log.info("[ticket] 工单配置:{} 选择工单模板成功:{}", ticketConfig.getId(), ticketTemplate);
        }
        // 4. 创建工单
        Ticket ticket = generateTicket(ticketConfig, ticketFlow, ticketTemplate, ticketDTO);
        if (log.isInfoEnabled()) {
            log.info("[ticket] 工单配置:{} 初始化工单成功:{}", ticketConfig.getId(), ticket.getId());
        }
        return ticket;
    }

    /**
     * 获取配置中的工单流程
     * 选择使用哪个工单流程.
     * 1. 从已启用的流程中, 按照优先级从高到低匹配
     * 2. 使用第一个满足工单流程条件设置的
     *
     * @param ticketConfigId 工单配置id
     * @param ticketFlowIds  流程ids
     * @return String
     * @author jy.zhao
     * @date 2021/8/17 21:22
     **/
    private TicketFlow chooseTicketFlow(String ticketConfigId, List<String> ticketFlowIds) {
        if (log.isInfoEnabled()) {
            log.info("[ticket] 获取工单流程");
        }
        TicketFlow matchedTicketFlow = null;

        List<TicketFlow> ticketFlows;
        if (CollUtil.isEmpty(ticketFlowIds)) {
            // 1. 从已启用的流程中, 按照优先级从高到低匹配
            ticketFlows = ticketFlowDao.findTicketFlowByStatus(ticketConfigId, TicketFlowStatusEnum.ENABLED.getIndex());
        } else {
            ticketFlows = ticketFlowDao.findTicketFlowById(ticketConfigId, ticketFlowIds);
        }
        if (log.isInfoEnabled()) {
            log.info("[ticket] 工单配置:{} 流程数据:{}", ticketConfigId, ticketFlows.size());
        }
        for (TicketFlow ticketFlow : ticketFlows) {
            // 无条件所有工单执行此流程，目前前端MatchCondition只会传1
            if (ticketFlow.getMatchCondition() == TicketFlowMatchConditionEnum.UNCONDITIONAL.getIndex()) {
                matchedTicketFlow = ticketFlow;
                break;
            }
        }
        if (log.isInfoEnabled()) {
            log.info("[ticket] 匹配到的工单流程:{} 工单流程无条件执行", matchedTicketFlow);
        }

        return matchedTicketFlow;
    }

    /**
     * 生成工单, 将流程和模板信息写入工单中, 并触发工单创建事件。在创建工单后, 工单依赖于自身保存的配置进行流转.
     *
     * @param ticketConfig   工单配置
     * @param ticketFlow     工单跟进人
     * @param ticketTemplate 工单模板
     * @return Ticket 工单信息
     * @author gy.liu
     * @date 2021/8/19
     */
    public Ticket generateTicket(TicketConfig ticketConfig, TicketFlow ticketFlow, TicketTemplateV2 ticketTemplate, CreateTicketDTO ticketDTO) {
        Ticket ticket = new Ticket();
        ticket.setSysId("ticket");
        ticket.setOrgId(ticketDTO.getOrgId());
        ticket.setSurveyId(ticketDTO.getSurveyId());
        ticket.setSurveyTitle(ticketDTO.getSurveyTitle());
        ticket.setName(ticketDTO.getTicketName());
        ticket.setOperationType(ticketDTO.getOperationType());
        if (Validator.isNotEmpty(ticketDTO.getAlertId())) {
            ticket.setAlertId(ticketDTO.getAlertId());
        }
        if (Validator.isNotNull(ticketDTO.getAlertRuleIdList())) {
            ticket.setAlertRuleIds(ticketDTO.getAlertRuleIdList());
        }
        if (Validator.isNotNull(ticketDTO.getAlertRecordId())) {
            ticket.setAlertRecordId(ticketDTO.getAlertRecordId());
        }
        ticket.setResId(ticketDTO.getResId());
        ticket.setTicketConfigId(ticketConfig.getId());
        ticket.setRegion(ticketDTO.getRegionId());
        ticket.setRegionName(ticketDTO.getRegionName());
        ticket.setStatus(TicketStatusEnum.CREATED.getIndex());
        // 设置工单编号
        ticket.setTicketNo(generateTicketNo(ticketDTO.getOrgId(), ticketDTO.getNeedDeal()));
        ticket.setTicketFlow(ticketFlow);
        ticket.setTicketTemplateV2(ticketTemplate);
        ticket.setType(TicketTypeEnum.UN_NEED_DEAL.getIndex());
        if (Boolean.TRUE.equals(ticketDTO.getNeedDeal())) {
            ticket.setType(TicketTypeEnum.NEED_DEAL.getIndex());
        }
        ticket.setTemplateDetailFields(ticketConfig.getTemplateDetailFields());
        ticket.setNeedRecord(ticketConfig.getNeedRecord());
        ticket.setMemberId(ticketDTO.getMemberId());
        ticket.setCurrentFollowNode(1);
        ticket.setCreatedName(ticketDTO.getCreatedName());
        ticket.setCreatedId(ticketDTO.getCreatedId());
        // 工单满足的触发条件的名称 2022-02-18 行动新增条件名称需求新增
        ticket.setTriggerNames(ticketDTO.getTriggerNames());
        return ticketDao.saveTicket(ticket);
    }

    /**
     * 获取工单编号 生成ticketNo yyyymmdd00001(五位seq)
     *
     * @param orgId    组织id
     * @param needDeal 需要处理
     * @return String 工单编号
     * @author jy.zhao
     * @date 2021/9/2 23:36
     **/
    private String generateTicketNo(String orgId, Boolean needDeal) {
        String redisKey = orgId.concat("_ticket_seq");
        Long redisSeq = redisService.incr(redisKey, 1);
        log.error("[ticket]: generateTicketNo:{} ", redisSeq);
        // 当天的结束时间
        LocalDateTime todayEndTime = LocalDateTimeUtil.endOfDay(DateUtil.getCurrentTime());
        redisService.expireAt(redisKey, DateUtil.toDate(todayEndTime));
        // 获取当前时间的年月日，然后转换为 yyyymmdd00001(五位seq)
        String dateStr = DateUtil.formatStringForTicket(todayEndTime);
        // 填充至五位数
        String seq = StrUtil.fillBefore(redisSeq.toString(), '0', 5);
        String ticketPrefix = "A";
        if (Boolean.TRUE.equals(needDeal)) {
            ticketPrefix = "T";
        }
        return ticketPrefix.concat(dateStr).concat(seq);
    }

    /**
     * 缓存
     *
     * @param ticket 工单编号日期字符串
     * @param orgId  组织id
     */
    public void cacheTicketNoForCopySample(Ticket ticket, String orgId) {
        boolean needDeal = false;
        if (ticket.getTicketNo().startsWith("T")) {
            needDeal = true;
        }
        String ticketNoDateString = ticket.getTicketNo().substring(1, 9);
        LocalDate ticketNoDate = LocalDate.parse(ticketNoDateString, DateTimeFormatter.ofPattern(DATETIME_PATTERN_FORTICKETNO));
        if (ticketNoDate.equals(LocalDate.now())) {
            ticket.setTicketNo(this.generateTicketNo(orgId, needDeal));
            log.error("[ticket]: orgId {}, ticketNo: {} ", orgId, ticket.getTicketNo());
        }
    }
}
